﻿//-----------------------------------------------------------------------
// <copyright file="SpriteGenApplication.cs" company="Richard Rose IT Ltd">
//     Copyright © 2008-2009 Richard Rose IT Ltd. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace RichardRose.Tools.SpriteGen
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.IO;
    using System.Runtime.Serialization;

    using RichardRose.Core;
    using RichardRose.Drawing.Imaging;

    /// <summary>
    /// Defines the SpriteGen application.
    /// </summary>
    public class SpriteGenApplication : CommandLineApplicationBase
    {
        #region Fields

        /// <summary>
        /// Defines all the settings for this instance of the application.
        /// </summary>
        private SpiteGenSettings settings = new SpiteGenSettings();

        #endregion Fields

        #region Properties

        /// <summary>
        /// Gets or sets the path of the configuration file.
        /// </summary>
        /// <value>The path to the configuration file.</value>
        [CommandLineArgument("config", Description = "A configuration file with all the settings specified in XML.", IsRequired = false)]
        [CommandLineArgumentDependency("Name", MutuallyExclusive = true)]
        public virtual string ConfigFile
        {
            get;
            set;
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Main entry point for the application.
        /// </summary>
        /// <param name="args">Arguments supplied via the command line.</param>
        public static void Main(string[] args)
        {
            SpriteGenApplication app = new SpriteGenApplication();
            app.Run(args);
        }

        /// <summary>
        /// Loads the command line arguments for the current application.
        /// </summary>
        /// <param name="args">The application arguments.</param>
        /// <remarks>
        /// Overrides the default implementation to ensure that this object's settings field
        /// is registered as a command line argument target.
        /// </remarks>
        protected override void ProcessArguments(string[] args)
        {
            this.RegisterArgumentTarget(this.settings);
            base.ProcessArguments(args);
        }

        /// <summary>
        /// Executes this instance of the application.
        /// </summary>
        /// <exception cref="T:System.NotSupportedException">
        /// If one of the files does not have a valid image format or if GDI+ does not support the pixel format of the file, this method throws an NotSupportedException exception.
        /// </exception>
        protected override void Execute()
        {
            // If a configuration file has been specified then load it.
            if (!string.IsNullOrEmpty(this.ConfigFile))
            {
                using (FileStream fs = File.OpenRead(this.ConfigFile))
                {
                    DataContractSerializer serializer = new DataContractSerializer(typeof(SpiteGenSettings));
                    this.settings = serializer.ReadObject(fs) as SpiteGenSettings;
                }
            }

            // Get a list of all the explicit images we need to process
            List<string> images = new List<string>();
            foreach (string image in this.settings.Images)
            {
                // Each image path can contain a wildcard and as a result it can represent multiple images.
                images.AddRange(SpriteGenApplication.GetImageFiles(image));
            }           

            // Construct a new CSS sprite generator.
            CssSpriteGenerator generator = new CssSpriteGenerator();
            generator.Height = this.settings.Width;
            generator.Width = this.settings.Width;
            generator.Spacing = this.settings.ImageSpacing;
            generator.Orientation = this.settings.ImageOrientation;

            using (Bitmap sprite = generator.Generate(images.ToArray()))
            {
                SpriteGenApplication.SaveSprite(sprite, this.settings.SpriteName, this.settings.SpriteFormat);
            }
        }

        /// <summary>
        /// Gets an array of all the image files identified by the path.
        /// </summary>
        /// <param name="path">The path to the image(s).</param>
        /// <returns>An array of all the image files.</returns>
        private static string[] GetImageFiles(string path)
        {
            string[] files = null;
            
            // Check to see if the path contains a wildcard.
            if (path.Contains("*"))
            {
                // Return the array of files.
                files = Directory.GetFiles(Path.GetDirectoryName(path), Path.GetFileName(path));
            }
            else
            {
                // No wild card specified so just return the supplied path.
                files = new string[] { path };
            }

            return files;
        }

        /// <summary>
        /// Saves the sprite to a file with the specified format.
        /// </summary>
        /// <param name="sprite">The sprite to save.</param>
        /// <param name="name">The name of the sprite.</param>
        /// <param name="format">The image format to save the sprite as.</param>
        private static void SaveSprite(Image sprite, string name, RichardRose.Drawing.Imaging.ImageFormat format)
        {
            if (format == RichardRose.Drawing.Imaging.ImageFormat.Png)
            {
                sprite.Save(name, System.Drawing.Imaging.ImageFormat.Png);
            }
            else if (format == RichardRose.Drawing.Imaging.ImageFormat.Gif)
            {
                // As we need to save as a gif, we will need to optimise the sprites color table. 
                OctreeQuantizer quantizer = new OctreeQuantizer(255, 8);
                quantizer.TransparencyThreshold = 100;
                using (Bitmap quantized = quantizer.Quantize(sprite))
                {
                    quantized.Save(name, System.Drawing.Imaging.ImageFormat.Gif);
                }
            }
        }

        #endregion Methods
    }
}
